<template>
  <n-layout-sider
    :width="320" :native-scrollbar="false" :collapsed="collapsed" collapse-mode="width" show-trigger="bar" bordered
    @update:collapsed="toggle"
  >
    <router-link to="/" #="{ navigate, href }" custom>
      <n-a class="logo" :href="href" @click="navigate">
        <n-image src="/penguin.gif"/> <!-- 样式在下面 -->
        <span>{{ store.state.name }}</span>
      </n-a>
    </router-link>
    <n-menu :value="currentKey" :default-expanded-keys="expandedKeys" :options="options" :root-indent="18" @update:value="k => { currentKey = k }" />
  </n-layout-sider>
</template>

<script lang="ts" setup>
import { h, ref, computed, watchEffect, inject } from 'vue'
import { useStore } from 'vuex'
import { useRoute, RouterLink } from 'vue-router'
import { MenuOption, NButton } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import { useMenus, Menu } from '../composables'
import { Icon } from '../components'

const store = useStore()

const collapsed = computed(() => store.state.sidebarCollapsed)

const toggle = async (): Promise<void> => await store.dispatch('toggleSidebarCollapse')

// TODO: loading state
const { data: menus } = useMenus()

const toggleTheme = inject('toggleTheme')

const themeItem = {
  id: '05ba',
  key: '05ba',
  label: () => h(NButton, {
    type: 'info',
    onClick: toggleTheme,
    innerText: 'Toggle Theme'
  }),
  icon: () => h(Icon, { type: 'flask' }),
  name: 'theme'
}

const { locale } = useI18n()

const toggleLang = () => {
  locale.value = (locale.value == 'zh_CN' ? 'en_US' : 'zh_CN')
}

const langItem = {
  id: '05bb',
  key: '05bb',
  label: () => h(NButton, {
    type: 'info',
    onClick: toggleLang,
    innerText: 'Toggle Lang'
  }),
  icon: () => h(Icon, { type: 'flask' }),
  name: 'lang'
}

const mapping = (items: Menu[], withTheme = false): MenuOption[] => {
  const ret = items.map(item => ({
    ...item,
    key: item.id,
    label: item.name != null ? () => h(RouterLink, { to: item }, { default: () => item.label }) : item.label,
    icon: item.icon != null ? () => h(Icon, { type: item.icon }) : undefined,
    children: item.children && mapping(item.children)
  }))
  if (withTheme) {
    ret.push(themeItem)
    ret.push(langItem)
  }
  //console.log(ret)
  return ret
}

const options = computed(() => (menus.value ? mapping(menus.value, true) : []))

const route = useRoute()
const currentKey = ref<string>('')
const expandedKeys = ref<string[]>([])

const routeMatched = (menu: Menu): boolean => {
  return route.name === menu.name && (menu.params == null || JSON.stringify(route.params) === JSON.stringify(menu.params))
}

const matchExpanded = (items: Menu[]): boolean => {
  let matched = false
  for (const item of items) {
    if (item.children != null) {
      matchExpanded(item.children) && expandedKeys.value.push(item.id)
    }
    if (routeMatched(item)) {
      currentKey.value = item.id
      matched = true
    }
  }
  return matched
}

watchEffect(() => menus.value && matchExpanded(menus.value))
</script>

<style scoped>
.logo {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  padding: 12px 20px;
  /* border-bottom: 1px solid var(--border-color); */
  background: var(--color);
  font-size: 1.8em;
  font-weight: 600;
  line-height: 1;
  text-decoration: none;
  transition: padding 0.3s var(--bezier), font-size 0.3s var(--bezier);
}

.n-layout-sider--collapsed .logo {
  padding: 8px;
  font-size: 0;
}

.logo .n-image {
  flex: 0 0 32px;
  height: 40px;
  margin-right: 12px;
  transition: margin 0.3s var(--bezier);
}

.n-layout-sider--collapsed .logo img {
  margin-right: 0;
}
</style>
